#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

#include "esp_at.h"
#include "at_chat.h"
#include "ringbuffer.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "esp_log.h"

static const char *TAG = "esp at";


/* Private function prototypes -----------------------------------------------*/
static void at_error(at_response_t *);
static void at_debug(const char *fmt, ...);
static int at_ready_handler(at_urc_info_t *info);

/* Private variables ---------------------------------------------------------*/
#define TTY_RXBUF_SIZE		 256
#define TTY_TXBUF_SIZE		 256
static unsigned char rxbuf[TTY_RXBUF_SIZE];
static unsigned char txbuf[TTY_TXBUF_SIZE];         /*发送缓冲区 */
ring_buf_t espat_rbrecv;                   /*环形缓冲区*/
ring_buf_t espat_rbsend;                   /*收发缓冲区管理*/

/**
 * @brief   定义AT控制器
 */
static at_obj_t *at_obj;

/**
 * @brief urc订阅表
 */
static const urc_item_t urc_table[] = 
{
    {.prefix = "ready",    .endmark = '\n', .handler = at_ready_handler},
};

/* Private functions ---------------------------------------------------------*/
#define EX_UART_NUM UART_NUM_0
#define PATTERN_CHR_NUM    (3)         /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/

#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
static QueueHandle_t uart0_queue;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for (;;) {
        //Waiting for UART event.
        if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch (event.type) {
            //Event of UART receving data
            /*We'd better handler data event fast, there would be much more data events than
            other types of events. If we take too much time on data event, the queue might
            be full.*/
            case UART_DATA:
                ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                ring_buf_put(&espat_rbrecv, dtmp, event.size);           /*将数据放入接收缓冲区*/  
                break;
            //Event of HW FIFO overflow detected
            case UART_FIFO_OVF:
                ESP_LOGI(TAG, "hw fifo overflow");
                // If fifo overflow happened, you should consider adding flow control for your application.
                // The ISR has already reset the rx FIFO,
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart0_queue);
                break;
            //Event of UART ring buffer full
            case UART_BUFFER_FULL:
                ESP_LOGI(TAG, "ring buffer full");
                // If buffer full happened, you should consider increasing your buffer size
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart0_queue);
                break;
            //Event of UART RX break detected
            case UART_BREAK:
                ESP_LOGI(TAG, "uart rx break");
                break;
            //Event of UART parity check error
            case UART_PARITY_ERR:
                ESP_LOGI(TAG, "uart parity error");
                break;
            //Event of UART frame error
            case UART_FRAME_ERR:
                ESP_LOGI(TAG, "uart frame error");
                break;
            //UART_PATTERN_DET
            case UART_PATTERN_DET:
                uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                int pos = uart_pattern_pop_pos(EX_UART_NUM);
                ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                if (pos == -1) {
                    // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                    // record the position. We should set a larger queue size.
                    // As an example, we directly flush the rx buffer here.
                    uart_flush_input(EX_UART_NUM);
                } else {
                    uart_read_bytes(EX_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                    uint8_t pat[PATTERN_CHR_NUM + 1];
                    memset(pat, 0, sizeof(pat));
                    uart_read_bytes(EX_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                    ESP_LOGI(TAG, "read data: %s", dtmp);
                    ESP_LOGI(TAG, "read pat : %s", pat);
                }
                break;
            //Others
            default:
                ESP_LOGI(TAG, "uart event type: %d", event.type);
                break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

static TaskHandle_t pUARTTaskHandle = NULL;
/*
 * @brief	    wifi串口初始化,如果已经初始化则值修改tx_pin,rx_pin
 * @param[in]   baudrate - 波特率
 * @return 	    none
 */
void esp_at_uart_config(int tx_pin, int rx_pin, int baud_rate)
{
    static bool uart_inited = false;
    if (uart_inited) {
        uart_set_pin(EX_UART_NUM, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
        return;
    }
    ring_buf_init(&espat_rbrecv, rxbuf, sizeof(rxbuf)); /*初始化环形缓冲区 */
    // ring_buf_init(&espat_rbsend, txbuf, sizeof(txbuf));/*初始化环形缓冲区 */
    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = baud_rate,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);

    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(EX_UART_NUM, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    // uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    //Reset the pattern queue length to record at most 20 pattern positions.
    // uart_pattern_queue_reset(EX_UART_NUM, 20);

    //Create a task to handler UART event from ISR
    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, &pUARTTaskHandle);
    uart_inited = true;
}

void esp_at_uart_deinit(void)
{
    vTaskDelete(pUARTTaskHandle);
    uart_driver_delete(EX_UART_NUM);
}

/*
 * @brief	    向串口发送缓冲区内写入数据并启动发送
 * @param[in]   buf       -  数据缓存
 * @param[in]   len       -  数据长度
 * @return 	    实际写入长度(如果此时缓冲区满,则返回len)
 */
static unsigned int uart_write(const void *buf, unsigned int len)
{   
    unsigned int ret;
    ret = uart_write_bytes(EX_UART_NUM, (const char *)buf, len);
    return ret;
}

/*
 * @brief	    读取串口接收缓冲区的数据
 * @param[in]   buf       -  数据缓存
 * @param[in]   len       -  数据长度
 * @return 	    (实际读取长度)如果接收缓冲区的有效数据大于len则返回len否则返回缓冲
 *              区有效数据的长度
 */
static unsigned int uart_read(void *buf, unsigned int len)
{
  return ring_buf_get(&espat_rbrecv, (unsigned char *)buf, len);
}

/*接收缓冲区空*/
static bool wifi_uart_rx_empty(void)
{
    return ring_buf_len(&espat_rbrecv) == 0;
}

/* 
 * @brief   wifi开机就绪事件
 */
static int at_ready_handler(at_urc_info_t *info)
{
    printf("ready...\r\n");
    return 0;
}

/**
 * @brief   wifi 通信异常处理
 */
static void at_error(at_response_t *r)
{
    printf("AT communication error\r\n");
    //执行重启作业
    //at_do_work(at_obj, NULL, wifi_reset_work);        
}

/* 
 * @brief    初始化回调
 */
static void at_init_callbatk(at_response_t *r)
{    
    if (r->code == AT_RESP_OK ) {
        printf("wifi Initialization successfully...\r\n");
        
    } else 
        printf("wifi Initialization failure...\r\n");
}


/**
 * @brief 单行命令
 */
void at_sysinfo(void)
{
    at_attr_t attr;
    at_attr_deinit(&attr);
    at_send_singlline(at_obj, &attr, "sysinfo");  
}
/**
 * @brief 单行命令
 */
void at_reset(void)
{
    at_attr_t attr;
    at_attr_deinit(&attr);    
    at_send_singlline(at_obj, &attr, "reset");  
}

static void get_temperature_cb(at_response_t *r)
{
    int state;
    if (r->code == AT_RESP_OK) {
        sscanf(r->prefix, "t:%d\r\n", &state);
        printf("temp:%d\r\n", state);
    }
}

void at_get_temperature(void){
    at_attr_t attr;
    at_attr_deinit(&attr);
    attr.prefix= "t:";
    attr.cb = get_temperature_cb;
    at_send_singlline(at_obj, &attr, "temperature");  
}

static void get_flow_rate_cb(at_response_t *r)
{
    int state;
    if (r->code == AT_RESP_OK) {
        sscanf(r->prefix, "flow_rate:%d\r\n", &state);
        printf("flow_rate:%d\r\n", state);
    }
}

void at_get_flow_rate(void){
    at_attr_t attr;
    at_attr_deinit(&attr);
    attr.prefix= "flow_rate:";
    attr.cb = get_flow_rate_cb;
    at_send_singlline(at_obj, &attr, "flow_rate");  
}

static void get_mode_cb(at_response_t *r)
{
    int state;
    if (r->code == AT_RESP_OK) {
        sscanf(r->prefix, "mode:%d\r\n", &state);
        printf("mode:%d\r\n", state);
    }
}

void at_get_mode(void){
    at_attr_t attr;
    at_attr_deinit(&attr);
    attr.prefix= "mode:";
    attr.cb = get_mode_cb;
    at_send_singlline(at_obj, &attr, "mode");  
}

void at_set_mode(int mode){
    at_attr_t attr;
    at_attr_deinit(&attr);
    at_exec_cmd(at_obj, &attr, "mode=%d", mode );
}

void at_set_onoff(int onoff){
    at_attr_t attr;
    at_attr_deinit(&attr);
    at_exec_cmd(at_obj, &attr, "onoff=%d", onoff );
}

void at_set_date_time(int year, int month, int day, int hour, int minute, int second){
    at_attr_t attr;
    at_attr_deinit(&attr);
    // 设置时间 YYYY/MM/DD HH:MM:SS
    at_exec_cmd(at_obj, &attr, "date=%04d/%02d/%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
}
/** 
 * @brief   AT适配器
 */
static const at_adapter_t  at_adapter = {
    .write         = uart_write,
    .read          = uart_read,
    .error         = NULL,
    .debug         = NULL,
    .urc_bufsize   = 256,
    .recv_bufsize  = 256
};

/* 
 * @brief    wifi初始化命令表
 */
/*static const char *wifi_init_cmds[] = {
    "AT",
    "ATE0",
    NULL
};
*/
/** 
 * @brief at通信处理线程
 */
void at_thread_task(void)
{
    at_obj_process(at_obj);
}

/* 
 * @brief    wifi初始化
 */
void esp_at_init(void)
{
    //at_attr_t attr;
    //创建AT控制器
    at_obj = at_obj_create(&at_adapter);
    //设置URC表
    at_obj_set_urc(at_obj, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));         

    // at_do_work(at_obj, NULL, wifi_reset_work);        
    
    // at_attr_deinit(&attr);
    // attr.cb = at_init_callbatk;
    // at_send_multiline(at_obj, &attr, wifi_init_cmds);  
    
    //GPIO测试
    // at_send_singlline(at_obj, &attr, "AT\r\n");
    // at_send_singlline(at_obj, &attr, "ATE0\r\n"); 

}
